package com.carrental.integration.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.carrental.integration.client.SmsClient;
import com.carrental.integration.service.SmsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 阿里云短信服务实现类
 * 通过调用阿里云短信服务API实现短信发送功能
 */
@Slf4j
@Service
public class AliyunSmsServiceImpl implements SmsService {

    @Resource
    private SmsClient smsClient;

    @Value("${third-party.sms.aliyun.access-key}")
    private String accessKey;

    @Value("${third-party.sms.aliyun.access-secret}")
    private String accessSecret;

    @Value("${third-party.sms.aliyun.sign-name}")
    private String signName;

    @Value("${third-party.sms.aliyun.template-code}")
    private String verificationCodeTemplateCode;

    private static final String NOTIFICATION_TEMPLATE_CODE = "SMS_123456789"; // 通知短信模板CODE
    private static final String MARKETING_TEMPLATE_CODE = "SMS_987654321"; // 营销短信模板CODE
    private static final String REGION_ID = "cn-hangzhou";
    private static final String FORMAT = "JSON";
    private static final String VERSION = "2017-05-25";
    private static final String ACTION = "SendSms";
    private static final String SIGNATURE_METHOD = "HMAC-SHA1";
    private static final String SIGNATURE_VERSION = "1.0";

    /**
     * 发送验证码短信
     *
     * @param phoneNumber 手机号码
     * @param code 验证码
     * @return 是否发送成功
     */
    @Override
    public boolean sendVerificationCode(String phoneNumber, String code) {
        Map<String, String> templateParams = new HashMap<>();
        templateParams.put("code", code);
        return sendSms(phoneNumber, verificationCodeTemplateCode, templateParams);
    }

    /**
     * 发送通知短信
     *
     * @param phoneNumber 手机号码
     * @param templateParams 模板参数
     * @return 是否发送成功
     */
    @Override
    public boolean sendNotification(String phoneNumber, Map<String, String> templateParams) {
        return sendSms(phoneNumber, NOTIFICATION_TEMPLATE_CODE, templateParams);
    }

    /**
     * 发送营销短信
     *
     * @param phoneNumber 手机号码
     * @param templateParams 模板参数
     * @return 是否发送成功
     */
    @Override
    public boolean sendMarketing(String phoneNumber, Map<String, String> templateParams) {
        return sendSms(phoneNumber, MARKETING_TEMPLATE_CODE, templateParams);
    }

    /**
     * 发送短信
     *
     * @param phoneNumber 手机号码
     * @param templateCode 短信模板CODE
     * @param templateParams 模板参数
     * @return 是否发送成功
     */
    private boolean sendSms(String phoneNumber, String templateCode, Map<String, String> templateParams) {
        try {
            // 生成时间戳
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
            df.setTimeZone(TimeZone.getTimeZone("GMT"));
            String timestamp = df.format(new Date());

            // 生成随机数
            String nonce = UUID.randomUUID().toString();

            // 构造请求参数
            Map<String, String> params = new TreeMap<>();
            params.put("AccessKeyId", accessKey);
            params.put("Action", ACTION);
            params.put("Format", FORMAT);
            params.put("PhoneNumbers", phoneNumber);
            params.put("RegionId", REGION_ID);
            params.put("SignName", signName);
            params.put("SignatureMethod", SIGNATURE_METHOD);
            params.put("SignatureNonce", nonce);
            params.put("SignatureVersion", SIGNATURE_VERSION);
            params.put("TemplateCode", templateCode);
            params.put("TemplateParam", JSON.toJSONString(templateParams));
            params.put("Timestamp", timestamp);
            params.put("Version", VERSION);

            // 计算签名
            String signature = calculateSignature(params, accessSecret);

            // 发送短信
            String result = smsClient.sendSms(
                    accessKey,
                    signature,
                    timestamp,
                    FORMAT,
                    SIGNATURE_METHOD,
                    SIGNATURE_VERSION,
                    nonce,
                    VERSION,
                    ACTION,
                    REGION_ID,
                    phoneNumber,
                    signName,
                    templateCode,
                    JSON.toJSONString(templateParams)
            );

            log.info("阿里云短信发送结果：{}", result);

            // 解析结果
            JSONObject jsonResult = JSON.parseObject(result);
            return "OK".equals(jsonResult.getString("Code"));
        } catch (Exception e) {
            log.error("发送短信异常", e);
            return false;
        }
    }

    /**
     * 计算签名
     *
     * @param params 请求参数
     * @param accessSecret 访问密钥
     * @return 签名
     * @throws Exception 异常
     */
    private String calculateSignature(Map<String, String> params, String accessSecret) throws Exception {
        // 构造待签名字符串
        StringBuilder stringToSign = new StringBuilder();
        stringToSign.append("POST&");
        stringToSign.append(URLEncoder.encode("/", StandardCharsets.UTF_8.name()));
        stringToSign.append("&");

        // 对参数进行排序并编码
        StringBuilder canonicalizedQueryString = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            canonicalizedQueryString.append("&")
                    .append(percentEncode(entry.getKey()))
                    .append("=")
                    .append(percentEncode(entry.getValue()));
        }

        // 去除第一个&
        String queryString = canonicalizedQueryString.toString().substring(1);
        stringToSign.append(percentEncode(queryString));

        // 计算HMAC值
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(new SecretKeySpec((accessSecret + "&").getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
        byte[] signData = mac.doFinal(stringToSign.toString().getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(signData);
    }

    /**
     * 百分号编码
     *
     * @param value 待编码的值
     * @return 编码后的值
     * @throws Exception 异常
     */
    private String percentEncode(String value) throws Exception {
        return value != null ? URLEncoder.encode(value, StandardCharsets.UTF_8.name())
                .replace("+", "%20")
                .replace("*", "%2A")
                .replace("%7E", "~") : null;
    }
} 